home *** CD-ROM | disk | FTP | other *** search
- /*
- * wKeys.c Moves and activates windows and screens via keystrokes.
- *
- * Copyright (c) 1987,1988 by Davide P. Cervone
- * You may use this code provided this copyright notice is left intact.
- */
-
- #include <exec/types.h>
- #include <libraries/dos.h>
- #include <exec/io.h>
- #include <exec/memory.h>
- #include <exec/interrupts.h>
- #include <devices/input.h>
- #include <devices/inputevent.h>
-
- #include "wKeys.h"
-
- static char *program = "wKeys";
- static int version = 2;
- static char *date = "April 1991";
- static char *author = "Copyright (c) 1987,1988,1991 by Davide P. Cervone";
- static int hversion = 0;
-
- static char *PortName = "wKeysPort";
- static char *handler = "L:wKeys-Handler"; /* the handler file */
- #define HANDLER &(handler[2]) /* without the "L:" */
-
-
- /*
- * This is the structure that holds the handler information between calls
- * to wKeys. We create a named, public message-port that points to
- * an instance of this structure so that we can find this information
- * when we are asked to remove the handler. The PortName is stored here
- * (NamedPort->mp_Node.ln_Name uses this area for it's name). The other
- * data are what we need in order to remove the handler and clean up properly.
- */
-
- struct HandlerBlock
- {
- char *PortName; /* name of the public, named message-port */
- struct Interrupt Handler; /* the handler added to the handler chain */
- struct IntuitionBase *Ibase; /* an error if the handler can't be found */
- struct LayersBase *Lbase; /* library base used by the handler */
- long Segment; /* pointer from LoadSeg() */
- struct HotKey *Keys; /* pointer to Key array */
- struct MsgPort *ReplyPort; /* the reply port for CLOSE-WINDOW */
- int KeyCount; /* size of Key array */
- };
- #define HANDLERINFOSIZE sizeof(struct HandlerBlock)
- #define NAMESIZE (strlen(PortName)+1)
-
- /*extern struct MsgPort *CreatePort();*/
- extern struct IOStdReq *CreateStdIO();
- extern struct MsgPort *FindPort(), *CreatePort();
- extern APTR AllocMem();
- extern long LoadSeg();
-
- #define INTUITION_REV 0L
- #define LAYERS_REV 0L
-
- struct IntuitionBase *IntuitionBase = NULL;
- struct LayersBase *LayersBase = NULL;
- extern struct SysBase *SysBase;
-
- struct MsgPort *InputPort = NULL; /* Port used to talk to Input.Device */
- struct IOStdReq *InputBlock = NULL; /* request block used with Input.Device */
- LONG InputDevice = 0; /* flag whether Input.Device is open */
- struct MsgPort *NamedPort = NULL; /* holds info needed to remove handler */
- struct MsgPort *ReplyPort = NULL; /* reply port for CLOSE-WINDOW */
- struct HandlerBlock *HandlerInfo = NULL; /* holds info stored in NamedPort */
-
- extern struct HotKeyItem *KeyList;
- extern struct HotKey *KeyArray;
- extern int KeyCount;
- #define KEYARRAYSIZE (KeyCount*sizeof(struct HotKey))
- extern void GetKeyArray();
-
-
- /*
- * DeleteNonSigPort()
- *
- * Deletes a message port with signal type PA_IGNORE. Based on
- * DeletePort() from the exec support functions documented in the RKM
- */
-
- void DeleteNonSigPort(thePort)
- struct MsgPort *thePort;
- {
- if (thePort->mp_Node.ln_Name) RemPort(thePort);
- thePort->mp_Node.ln_Type = 0xFF;
- thePort->mp_MsgList.lh_Head = (struct Node *) -1;
- FreeMem(thePort,(ULONG)sizeof(struct MsgPort));
- }
-
-
- /*
- * CreateNonSigPort()
- *
- * Creates a message port with signal type PA_IGNORE. Based on
- * CreatePort() from the exec support functions documented in the RKM.
- */
-
- struct MsgPort *CreateNonSigPort(name,pri)
- char *name;
- BYTE pri;
- {
- struct MsgPort *thePort;
-
- thePort = (struct MsgPort *)AllocMem((ULONG)sizeof(struct MsgPort),
- MEMF_PUBLIC | MEMF_CLEAR);
- if (thePort)
- {
- thePort->mp_Node.ln_Name = name;
- thePort->mp_Node.ln_Pri = pri;
- thePort->mp_Node.ln_Type = NT_MSGPORT;
-
- thePort->mp_Flags = PA_IGNORE;
- thePort->mp_SigBit = 0;
- thePort->mp_SigTask = NULL;
-
- if (name)
- AddPort(thePort);
- else
- NewList(&(thePort->mp_MsgList));
- }
- return(thePort);
- }
-
-
- /*
- * DoExit()
- *
- * General purpose exit routine. If 's' is not NULL, then print an
- * error message with up to three parameters. Free any memory, close
- * any open device, delete any ports, close any libraries, etc.
- */
-
- void DoExit(s,x1,x2,x3)
- char *s, *x1, *x2, *x3;
- {
- long status = RETURN_OK;
- struct HotKeyItem *TempKey;
-
- if (s != NULL)
- {
- printf(s,x1,x2,x3);
- printf("\n");
- status = RETURN_ERROR;
- }
- if (InputDevice) CloseDevice(InputBlock);
- if (InputBlock) DeleteStdIO(InputBlock);
- if (InputPort) DeletePort(InputPort);
- if (NamedPort) DeleteNonSigPort(NamedPort);
- if (ReplyPort) DeleteNonSigPort(ReplyPort);
- if (HandlerInfo)
- {
- if (HandlerInfo->PortName) FreeMem(HandlerInfo->PortName,NAMESIZE);
- FreeMem(HandlerInfo,HANDLERINFOSIZE);
- }
- if (KeyArray) FreeMem(KeyArray,KEYARRAYSIZE);
- while (KeyList)
- {
- TempKey = KeyList;
- KeyList = KeyList->Next;
- FreeMem(TempKey,sizeof(*TempKey));
- }
- if (IntuitionBase) CloseLibrary(IntuitionBase);
- if (LayersBase) CloseLibrary(LayersBase);
- exit(status);
- }
-
-
- /*
- * CheckLibOpen()
- *
- * General library open routine. It opens a library and sets a pointer
- * to it. It checks that the library was openned successfully.
- */
-
- static void CheckLibOpen(lib,name,rev)
- APTR *lib;
- char *name;
- int rev;
- {
- extern APTR OpenLibrary();
-
- if ((*lib = OpenLibrary(name,(LONG)rev)) == NULL)
- DoExit("Can't open '%s'\n",name);
- }
-
-
- /*
- * Macros that make memory allocation easier.
- */
- #define NEW(s,var) (var = (struct s *)New("var",sizeof(struct s)))
- #define NEWCHAR(var,s) (var = (char *)New("var",s))
-
-
- /*
- * New()
- *
- * Allocate public memory of a given size and set it to all zeros. If there
- * is not enough memory, then exit with an error, otherwise return the
- * pointer to the newly allocated memory.
- */
-
- APTR New(name,size)
- char *name;
- int size;
- {
- APTR ptr;
-
- if ((ptr = AllocMem(size,MEMF_PUBLIC | MEMF_CLEAR)) == NULL)
- DoExit("Can't Get Memory for '%s'",name);
- return(ptr);
- }
-
-
- /*
- * TellInputDevice()
- *
- * Create a port and I/O block, and open the input device. Set up the
- * I/O block to add or remove the input handler, and send the request
- * to the input device. Finally, close the device and delete the
- * I/O block and port.
- */
-
- static void TellInputDevice(function)
- int function;
- {
- long status;
-
- if ((InputPort = CreatePort(0,0)) == NULL) DoExit("Can't Create Port");
- if ((InputBlock = CreateStdIO(InputPort)) == NULL)
- DoExit("Can't Create Standard IO Block");
- InputDevice = (OpenDevice("input.device",0,InputBlock,0) == 0);
- if (InputDevice == FALSE) DoExit("Can't Open 'input.device'");
-
- InputBlock->io_Command = (long) function;
- InputBlock->io_Data = (APTR) &(HandlerInfo->Handler);
- if (status = DoIO(InputBlock)) DoExit("Error from DoIO: %ld",status);
-
- CloseDevice(InputBlock);
- DeleteStdIO(InputBlock);
- DeletePort(InputPort);
- }
-
-
- /*
- * CreateHandler()
- *
- * Open the libraries needed by the input handler and store their locations
- * in the HandlerInfo structure (so we can close them later). Try to
- * LoadSeg() the handler. If it is not in the current directory, try the
- * L: directory. Exit with an error if the handler can't be found.
- * Convert the segment pointer into a pointer to the Setup() routine (the
- * first routine in the handler executable). Call Setup() and pass it
- * the pointers to the libraries that it will need to use. Setup() returns
- * a pointer to the actual handler routine that should be added into the
- * input handler chain. Store this in the HandlerInfo structure so we
- * can use it to remove the handler later. Set the handler priority to
- * 51 so that it is ahead of Intuition.
- *
- * Finally, add the handler in the chain and tell the user that the
- * handler has been installed.
- */
-
- static void CreateHandler()
- {
- long (*Setup)();
-
- CheckLibOpen(&IntuitionBase,"intuition.library",INTUITION_REV);
- CheckLibOpen(&LayersBase,"layers.library",LAYERS_REV);
-
- HandlerInfo->Ibase = IntuitionBase;
- HandlerInfo->Lbase = LayersBase;
- if ((HandlerInfo->Segment = LoadSeg(HANDLER)) == NULL)
- if ((HandlerInfo->Segment = LoadSeg(handler)) == NULL)
- DoExit("Can't Load '%s'",handler);
- Setup = (long (*)()) ((HandlerInfo->Segment << 2) + 4);
- HandlerInfo->Handler.is_Code =
- (void (*)()) ((*Setup)(IntuitionBase,LayersBase,SysBase,
- KeyArray,KeyCount,ReplyPort,&hversion));
- HandlerInfo->Handler.is_Node.ln_Pri = 51;
- HandlerInfo->Keys = KeyArray;
- HandlerInfo->KeyCount = KeyCount;
- HandlerInfo->ReplyPort = ReplyPort;
-
- TellInputDevice(IND_ADDHANDLER);
- printf("%s v%d.%d (%s) Installed\n",program,version,hversion,date);
- }
-
-
- /*
- * Delete Handler()
- *
- * Retreive the library pointers from the HandlerInfo structure, where
- * we stored them when we originally installed the handler, then remove
- * the handler from the input handler chain. Tell the user that the
- * handler is gone, and then close the libraries that are no longer needed.
- */
-
- static void DeleteHandler()
- {
- IntuitionBase = HandlerInfo->Ibase;
- LayersBase = HandlerInfo->Lbase;
- KeyArray = HandlerInfo->Keys;
- KeyCount = HandlerInfo->KeyCount;
- ReplyPort = HandlerInfo->ReplyPort;
-
- TellInputDevice(IND_REMHANDLER);
- UnLoadSeg(HandlerInfo->Segment);
- printf("%s Removed\n",program);
-
- FreeMem(KeyArray,KEYARRAYSIZE);
- CloseLibrary(IntuitionBase);
- CloseLibrary(LayersBase);
- }
-
-
- /*
- * main()
- *
- * Check if a message port with our name already exists.
- * If not, then the handler is not already installed, so:
- * Allocate a new HandlerInfo structure and initialize the port name.
- * Create a public, named message-port (we will look for this the next
- * time wKeys is called).
- * Make the message port point to the HandlerInfo structure so we
- * can use it later when the user asks us to remove the handler.
- * Note that the port is not actually used for putting and getting
- * messages, so the Task field is never used, so we can take it for
- * our own uses.
- * Get a port to use as a reply port for CLOSE-WINDOW intuimessages.
- * Finally, add the input handler into the chain.
- * Otherwise, the port exists, so wKeys already is installed:
- * Retreive the HandlerInfo poiner from the port, and remove the
- * handler from the input handler chain.
- * Free the memory used by the HandlerInfo, and delete the message ports.
- */
-
- void main(argc,argv)
- int argc;
- char **argv;
- {
- NamedPort = FindPort(PortName);
- if (NamedPort == NULL)
- {
- NEW(HandlerBlock,HandlerInfo);
- NEWCHAR(HandlerInfo->PortName,NAMESIZE);
- strcpy(HandlerInfo->PortName,PortName);
- if ((NamedPort = CreateNonSigPort(HandlerInfo->PortName,0)) == NULL)
- DoExit("Can't Create Message Port '%s'",PortName);
- if ((ReplyPort = CreateNonSigPort(NULL,0)) == NULL)
- DoExit("Can't Create Reply Port");
- NamedPort->mp_SigTask = (struct Task *)HandlerInfo;
- GetKeyArray(argc,argv);
- CreateHandler();
- } else {
- HandlerInfo = (struct HandlerBlock *)(NamedPort->mp_SigTask);
- DeleteHandler();
- FreeMem(HandlerInfo->PortName,NAMESIZE);
- FreeMem(HandlerInfo,HANDLERINFOSIZE);
- DeleteNonSigPort(ReplyPort);
- DeleteNonSigPort(NamedPort);
- }
- }
-